using System;
using System.Collections.Generic;

namespace TestProject.Test.Base
{
    /// <summary>
    /// Provides a standard set of utilities to be used by tests for BusinessObjects in this
    /// application.  In addition, each tested BO has a TestUtils class used to create
    /// random test packs.
    ///
    /// You can safely add additional utilities to this particular file since it is
    /// only written once.  If you are adding utilities for a specific BO only, rather
    /// add them to the TestUtils class for that BO (usually title TestUtilsCar if Car is the BO).
    /// </summary>
    public class TestUtilsShared
    {
        private static Random _randomGenerator;

        protected static Random Random
        {
            get
            {
                if (_randomGenerator == null) _randomGenerator = new Random();
                return _randomGenerator;
            }
        }

        public static int GetRandomInt()
        {
            return GetRandomInt(100000); 
        }
        
        public static int GetRandomInt(int max)
        {
            return Random.Next(0, max); 
        }

        public static int GetRandomInt(int min,int max)
        {
            return Random.Next(min, max); 
        }

        public static string GetRandomString()
        {
            return GetRandomInt().ToString(); 
        }
        
        public static string GetRandomString(int maxLength)
        {            
            if (maxLength > 9) maxLength = 9;
            int max = Convert.ToInt32(Math.Pow(10, maxLength)) - 1;
            return GetRandomInt(max).ToString();          
        }
        
        public static string GetRandomString(int minLength, int maxLength)
        {
            if (minLength > 9) minLength = 9;
            int min = Convert.ToInt32(Math.Pow(10, minLength)) - 1;
            if (maxLength > 9) maxLength = 9;
            int max = Convert.ToInt32(Math.Pow(10, maxLength)) - 1;
            return GetRandomInt(min,max).ToString();
        }
        
        public static bool GetRandomBoolean()
        {
            return (GetRandomInt(100000) > 50000); 
        }
        
        public static DateTime GetRandomDate()
        {
            return DateTime.Now;
        }
        
        public static DateTime GetRandomDate(string max)
        {
            string start = DateTime.MinValue.ToString("yyyy/MM/dd");
            return GetRandomDate(start,max);
        }
        
        public static DateTime GetRandomDate(string min, string max)
        {
            DateTime start = DateTime.Parse(min);
            
            int range = (DateTime.Parse(max) - start).Days;
            return start.AddDays(TestUtilsShared.GetRandomInt(range));
        }
        
        /// <summary>
        /// Takes a lookup list generated by Habanero and randomly selects a value
        /// from the list
        /// </summary>
        public static object GetRandomLookupListValue(Dictionary<string, string> lookupList)
        {
            string[] values = new string[lookupList.Count];
            lookupList.Values.CopyTo(values, 0);
            return values[TestUtilsShared.GetRandomInt(0, values.Length - 1)];
        }

        public static TEnum GetRandomEnum<TEnum>()
            where TEnum : struct
        {
            return GetRandomEnum<TEnum>(null);
        }

        public static TEnum GetRandomEnum<TEnum>(TEnum? excluded)
            where TEnum : struct
        {
            Array values = Enum.GetValues(typeof(TEnum));
            int randomIndex = GetRandomInt(0, values.Length);
            TEnum value = (TEnum)values.GetValue(randomIndex);
            if (excluded.HasValue && excluded.Value.Equals(value))
            {
                return GetRandomEnum(excluded);
            }
            return value;
        }
        
        /// <summary>
        /// Waits for the garbage collector to clear dereferenced objects in order
        /// to ensure accurate testing
        /// </summary>
        public static void WaitForGC()
        {
            GC.Collect();
            GC.WaitForPendingFinalizers();
        }
    }
}